#include <iostream>
#include "vlcontroller.h"

void onMouse(int event, int x, int y, int flags, void* param);

VLController::VLController()
{
    vlModel = &(vlView.vlModel);
    vlView.showSettings();
    video = vlView.choosingVideoSource();
    mask = NULL;

    if(video.ROI.count() > 1 &&
            video.ROI.first().x == video.ROI.last().x &&
            video.ROI.first().y == video.ROI.last().y)
    {
        bUsingROI = true;
    }else
        bUsingROI = false;
}

void VLController::virtualLoop()
{
    CvCapture* capture = 0;

    if(video.sourceType == URL)
        capture = cvCreateFileCapture(video.Source());
    else
        capture = cvCaptureFromFile(video.Source());
    int fps;
    char key;

    if(capture)
    {
        IplImage* frame = cvQueryFrame(capture);
        fps = ( int )cvGetCaptureProperty( capture, CV_CAP_PROP_FPS );
        mask = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);
        negMask = cvCloneImage(mask);
        if(bUsingROI)
            recomputeMask();

        IplImage* grayFrame = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);
        IplImage* grayFrame_last = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);
        IplImage* diff = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);

        float ratio = 0;
        QTime timeWait = QTime::currentTime();
        bool bWait = true;
        bool vlOn = false;
        bool vlState = false;

        cvZero(grayFrame_last);
        while(frame)
        {
            cvCvtColor(frame, grayFrame, CV_BGR2GRAY);
            cvAndS(grayFrame, cvScalar(1), grayFrame, mask);
            vlView.showDebugImage("frame: illumination", grayFrame);

            cvAbsDiff(grayFrame, grayFrame_last, diff);
            vlView.showDebugImage("Frame difference", diff);

            cvThreshold(diff, diff, 50, 255, CV_THRESH_BINARY);
            vlView.showDebugImage("Binary image", diff);

            ratio = (float) cvCountNonZero(diff)/countZero;

            if(ratio > video.motionThreshold/100.)
            {
                if(!vlOn)
                {
                    vlOn = true; //switch
                    timeWait = QTime::currentTime();
                    bWait = !bWait;
                }
            }
            else
            {
                if(vlOn)
                {
                    vlOn = false; //switch
                    timeWait = QTime::currentTime();
                    bWait = !bWait;
                }
            }

            if(bWait && timeWait.msecsTo(QTime::currentTime()) > video.timeSwitch)
            {
                vlState = vlOn;
                bWait = false;
            }

            vlView.showMainImage(frame, vlState, bUsingROI, video.ROI, negMask);
            cvCopyImage(grayFrame, grayFrame_last);

            key = cvWaitKey(1000/fps-BOOST_AHH);
            if(key == 27)
                break;
            else if(key == 'v'){
                vlModel->switchVerboseMode();
                cvDestroyAllWindows();
                cvNamedWindow(MAIN_WINDOW_NAME_VL,0);
                cvSetMouseCallback(MAIN_WINDOW_NAME_VL, ::onMouse,NULL);
            }
            else if(key == 'r')
            {
                bUsingROI = false;
                ROI_clear();
            }else if(key == 'q')
                exit(1);
            frame = cvQueryFrame(capture);
        }

        cvReleaseImage(&grayFrame);
        cvReleaseImage(&grayFrame_last);
        cvReleaseImage(&diff);
        cvReleaseImage(&mask);
        cvReleaseImage(&negMask);
        cvReleaseCapture(&capture);
    }
}

void VLController::run()
{
    virtualLoop();
}

void VLController::ROI_clear()
{
    video.ROI.clear();
    vlModel->clearROI();
    bUsingROI = false;
}

void VLController::ROI_add_point(CvPoint point)
{
    if(!bUsingROI)
        video.ROI.append(point);
}

void VLController::ROI_apply()
{
    if(video.ROI.count() > 1)
    {
        CvPoint point = video.ROI[0];
        video.ROI.append(point);

        vlModel->setROI(video.ROI);
        bUsingROI = true;
        recomputeMask();
    }
}

void VLController::recomputeMask()
{
    if(mask)
    {
        cvSet(mask, cvScalar(255));
        CvPoint* pPoint = new CvPoint[video.ROI.count()];
        for(int i = 0; i < video.ROI.count() - 1; i++)
        {
            pPoint[i] = video.ROI[i];
        }

        cvFillConvexPoly(mask, pPoint,video.ROI.count() -1, cvScalar(0));
        delete pPoint;

        cvNot(mask, negMask);

        countZero = mask->height*mask->width - cvCountNonZero(mask);
    }
}
